﻿// Copyright (c) 2007-2021 西安交通信息投资营运有限公司 版权所有
// 作者:吕艳阳

using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using XCI.Extensions;
using XCI.Helper;

namespace XCI.Core
{
    public static class Startup
    {
        /// <summary>
        /// 应用启动
        /// </summary>
        /// <param name="args">参数</param>
        public static void Run<T>(params string[] args) where T : AppHandler, new()
        {
            App.Handler = new T();
            App.StartupArgs = FromStartupArgs(args);
            App.SplashScreenType = App.Handler.GetSplashScreenType();
            App.Setting = App.Handler.LoadAppSetting();
            SingletonRun(RunCore);
        }

        /// <summary>
        /// 启动核心逻辑
        /// </summary>
        private static void RunCore()
        {
            ThemeConfig.Get().InitAppTheme();
            SplashScreenHelper.SetSplashScreenType(App.SplashScreenType);
            SplashScreenHelper.Show("正在启动...");

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = new CultureInfo("zh-Hans");
            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
            Application.ThreadException += (s, e) => { App.Handler.OnGlobalExceptionHandler(e.Exception); }; //处理UI线程异常
            AppDomain.CurrentDomain.UnhandledException += (s, e) => { App.Handler.OnGlobalExceptionHandler(e.ExceptionObject as Exception); };//处理非UI线程异常

            SplashScreenHelper.Show("正在初始化组件...");
            App.Handler.OnApplicationInit();
            App.WaitFormType = App.Handler.GetWaitFormType();//等待窗体类型
            WaitFormHelper.SetWaitFormType(App.WaitFormType);
            App.SettingStore = App.Handler.CreateSettingStore(); //配置存储对象
            App.Validator = App.Handler.CreateValidator(); //模型验证器
            App.ContainerData = App.Handler.CreateContainerForm();//容器数据操作器
            App.Excel = App.Handler.CreateExcel(); //Excel导入导出对象

            App.ClientOsName = NativeMethods.GetWindowsName(); //客户端操作系统名称
            App.ClientOsVersion = NativeMethods.GetWindowsVersion(); //客户端操作系统版本
            App.ClientDevExpressVersion = WinFormHelper.GetDevExpressVersion();  //客户端DevExpress控件版本
            App.ClientXCIVersion = WinFormHelper.GetXCIVersion();  //客户端XCI框架版本

            //服务器对象
            App.Client = App.Handler.CreateWebApiClient(App.Setting.Server);
            App.FileClient = App.Handler.CreateFileWebApiClient(App.Setting.FileServer ?? App.Setting.Server) ?? App.Client;

            //软件更新
            if (App.Setting.EnableUpgrade) App.Handler.Upgrade(SplashScreenHelper.Show);

            //同步日期
            if (App.Setting.EnableSyncDateTime) App.Handler.SyncDateTime(SplashScreenHelper.Show);

            //主界面
            SplashScreenHelper.Show("即将完成...");
            App.StartupForm = App.Handler.OnCreateStartupForm();

            SplashScreenHelper.Hide();
            if (App.StartupForm != null)
            {
                try
                {
                    Application.Run(App.StartupForm);
                    App.Handler.OnApplicationExit();
                }
                catch (Exception e)
                {
                    MessageBoxHelper.ShowError(e.Message);
                }
            }
        }

        /// <summary>
        /// 单实例启动程序
        /// </summary>
        /// <param name="action">启动回调</param>
        private static void SingletonRun(Action action)
        {
            if (App.Setting.EnableSingleton)
            {
                var mutex = new Mutex(true, App.Setting.Id, out var hasMutex);
                if (hasMutex)
                {
                    action();
                    mutex.ReleaseMutex();
                }
                else
                {
                    App.Handler.OnSingletonExceptionHandler();
                    Environment.Exit(0);
                }
            }
            else
            {
                action();
            }
        }


        /// <summary>
        /// 退出当前程序
        /// </summary>
        public static void Exit()
        {
            App.Handler.OnApplicationExit();
            System.Environment.Exit(0);
        }

        /// <summary>
        /// 重启当前程序
        /// </summary>
        public static void Restart(Map args = null)
        {
            var map = new Map();
            map.Merge(args);
            var p = Process.GetCurrentProcess();
            map.Set("cmd", "restart");
            map.Set("processId", p.Id);
            map.Set("processName", p.ProcessName);
            map.Set("path", Path.GetFileName(Application.ExecutablePath));
            RunDaemon(map);
        }


        /// <summary>
        /// 当前是否重启状态
        /// </summary>
        public static bool IsRestart()
        {
            return IsRestart(App.StartupArgs);
        }

        /// <summary>
        /// 当前是否重新登录状态
        /// </summary>
        public static bool IsRestart(Map args)
        {
            return args.TryGetValue("cmd", out object val) && val.ToStringOrEmpty().Equals("restart");
        }

        /// <summary>
        /// 杀掉当前程序进程
        /// </summary>
        public static void Kill()
        {
            App.Handler.OnApplicationExit();
            var map = new Map();
            var p = Process.GetCurrentProcess();
            map.Set("cmd", "kill");
            map.Set("processId", p.Id);
            map.Set("processName", p.ProcessName);
            RunDaemon(map);
        }

        /// <summary>
        /// 更新当前程序(更新包解压并替换文件)
        /// </summary>
        public static void Upgrade(string packageListString)
        {
            var map = new Map();
            var p = Process.GetCurrentProcess();
            map.Set("cmd", "upgrade");
            map.Set("processId", p.Id);
            map.Set("processName", p.ProcessName);
            map.Set("path", Path.GetFileName(Application.ExecutablePath));
            map.Set("list", packageListString);
            RunDaemon(map);
        }

        /// <summary>
        /// 启动守护进程
        /// </summary>
        /// <param name="args">启动参数集合</param>
        private static void RunDaemon(Map args)
        {
            try
            {
                Process.Start("daemon.exe", ToStartupArguments(args));
            }
            catch (Exception)
            {
                MessageBox.Show("系统守护进程启动失败，可能被杀毒软件误杀，文件丢失，请重新安装应用程序", "系统", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// 解析启动参数为Map集合
        /// </summary>
        /// <param name="args">启动参数集合</param>
        public static Map FromStartupArgs(string[] args)
        {
            var map = new Map();
            if (args == null || args.Length == 0) return map;

            foreach (var item in args)
            {
                if (string.IsNullOrWhiteSpace(item)) continue;
                var argsArray = item.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
                if (argsArray.Length != 2) continue;
                var key = argsArray[0].ToStringOrEmpty();
                var value = argsArray[1].ToStringOrEmpty();
                map[key] = value;
            }
            return map;
        }

        /// <summary>
        /// 启动参数集合转为启动字符串
        /// </summary>
        /// <param name="args">启动参数集合</param>
        public static string ToStartupArguments(Map args)
        {
            if (args == null || args.Count == 0) return string.Empty;
            var sb = new StringBuilder();
            foreach (var pair in args)
            {
                sb.Append($"{pair.Key.ToStringOrEmpty()}={pair.Value.ToStringOrEmpty()} ");
            }
            return sb.ToString();
        }
    }
}